package com.aiwiown.snackmq.cluster.routing.exchange;

import com.aiwiown.snackmq.cluster.routing.Binding;
import com.aiwiown.snackmq.cluster.routing.Exchange;
import com.aiwiown.snackmq.common.message.Message;
import com.aiwiown.snackmq.common.routing.ExchangeType;
import lombok.Getter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * FanoutExchange 类实现了 Exchange 接口，表示一个扇出交换机。
 * 扇出交换机会将接收到的消息广播到所有绑定到它的队列中，不考虑消息的 routingKey。
 */
public class FanoutExchange implements Exchange {
    private static final long serialVersionUID = 301184317535465512L;
    // 序列化版本ID，用于序列化兼容性

    // 交换机名称，通过getter方法暴露
    @Getter
    private final String name;

    // 存储绑定信息的列表，使用CopyOnWriteArrayList以提高线程安全
    private final List<Binding> bindings = new CopyOnWriteArrayList<>();

    /**
     * 构造函数，初始化交换机名称。
     *
     * @param name 交换机的名称
     */
    public FanoutExchange(String name) {
        this.name = name;
    }

    /**
     * 获取交换机的类型，对于FanoutExchange来说，类型始终为FANOUT。
     *
     * @return 交换机类型为 ExchangeType.FANOUT
     */
    @Override
    public ExchangeType getType() {
        return ExchangeType.FANOUT;
    }

    /**
     * 向交换机添加一个新的绑定。
     *
     * @param binding 要添加的绑定对象
     */
    @Override
    public void addBinding(Binding binding) {
        this.bindings.add(binding);
    }

    /**
     * 从交换机移除一个绑定。
     *
     * @param binding 要移除的绑定对象
     */
    @Override
    public void removeBinding(Binding binding) {
        this.bindings.remove(binding);
    }

    /**
     * 根据消息的routingKey将消息路由到绑定的队列。
     * 对于FanoutExchange，忽略routingKey，将消息路由到所有绑定的队列。
     *
     * @param message 要路由的消息对象
     * @return 包含所有绑定队列名称的列表
     */
    @Override
    public List<String> route(Message message) {
        return bindings.stream()
                .map(Binding::getQueueName)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 获取所有绑定信息的不可修改列表。
     * 返回不可修改的副本以保证线程安全和数据一致性。
     *
     * @return 包含所有绑定信息的不可修改列表
     */
    @Override
    public List<Binding> getBindings() {
        return Collections.unmodifiableList(new ArrayList<>(this.bindings));
    }
}
